package gameoflive;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;


public class GameOfLive
{
    private static final int MAX_CELLS = 2048 * 64;

    private static GameOfLive instance;
    
    public static synchronized GameOfLive getInstance()
    {
        if (instance == null)
        {
            instance = new GameOfLive();
        }
        return instance;
    }
    
    private Dimension maxXY;
    
    private List<Cell> cells;
    
    private int generation;
    private int livingCells = 0;
    private int livingCellsIdentical = 0;

    private GameOfLive()
    {
        this.cells = new ArrayList<Cell>();
    }
    
    public Dimension getMaxXgetHeight()
    {
        return maxXY;
    }
    
    public int getGeneration()
    {
        return generation;
    }
    
    public Cell getCell(Dimension position)
    {
        return getCell((int) position.getWidth(), (int) position.getHeight());
    }
    
    public Cell getCell(int x, int y)
    {
        if (x < 0 || x > maxXY.getWidth())
        {
            throw new IndexOutOfBoundsException(x + " not in 0-" + maxXY.getWidth());
        }
        if (y < 0 || y > maxXY.getHeight())
        {
            throw new IndexOutOfBoundsException(y + " not in 0-" + maxXY.getHeight());
        }
        Cell cell = null;
        int index = calculateIndex(x, y, (int) maxXY.getWidth());
        if (index == cells.size())
        {
            cells.add(new Cell(x, y, false, false));
        }
        cell = cells.get(index);
//        Game.log("getCell: " + index + " = " + cell);
        return cell;
    }
    
    private int calculateIndex(int x, int y, int maxWidth)
    {
        int index = 0;
        index = x + y * maxWidth;
//        Game.log("calculateIndex: x=" + x + ", y=" + y + " = " + index);
        return index;
    }
    
    private void buildMap(int width, int height)
    {
        Game.log("buildMap()");
        // Anzahl Zellen
        maxXY = new Dimension(width, height);
        // Liste generieren
        this.cells = new ArrayList<>(cells);
        for (int y = 0; y < maxXY.getHeight(); y++)
        {
            for (int x = 0; x < maxXY.getWidth(); x++)
            {
                Cell cell = getCell(x, y);
            }
        }
        
    }
    
    public List<Cell> getCells()
    {
        return cells;
    }
    
    public boolean prepareNextGeneration()
    {
        generation++;
//        Game.log("prepareNextGeneration: " + generation);
        List<Cell> cells = getCells();
        for (Cell cell : cells)
        {
            int livingNeighbors = cell.countLivingNeighbors();
            boolean surviving = cell.isAlive();
            if (cell.isAlive())
            {
                if (livingNeighbors == 2 || livingNeighbors == 3)
                {
                    surviving = true;
                }
                else
                {
                    surviving = false;
                }
            }
            else
            {
                if (livingNeighbors == 3)
                {
                    surviving = true;
                }
            }
//            Game.log("Cell surving: " + surviving);
            cell.setSurviving(surviving);
        }
        int alive = 0;
        for (Cell cell : cells)
        {
            cell.setAlive(cell.isSurviving());
            if (cell.isAlive())
            {
                alive++;
            }
        }
        if (alive == livingCells)
        {
            livingCellsIdentical++;
        }
        else
        {
            livingCellsIdentical = 0;
        }
        livingCells = alive;
//        Game.log("Generation " + getGeneration() + "; " + livingCells + " Living Cells");
        return livingCells == 0 || livingCellsIdentical < 150;
    }
    
    public void initGeneration(int x, int y)
    {
        Game.log("initGeneration: " + (x * y) + " cells");
        buildMap(x, y);
        // Lebende Zellen generieren
        Random RANDOM = new Random(System.currentTimeMillis());
        List<Dimension> livingCells = new ArrayList<Dimension>();
        do
        {
            Dimension position = new Dimension(RANDOM.nextInt((int) (maxXY.getWidth() + 1)), RANDOM.nextInt((int) (maxXY.getHeight() + 1)));
            if (livingCells.contains(position) == false)
            {
                livingCells.add(position);
            }
        }
        while (livingCells.size() < ((x * y) / 2));
        for (Cell cell : getCells())
        {
            if (livingCells.contains(cell.getPosition()))
            {
                cell.setAlive(true);
                cell.setSurviving(true);
            }
        }
    }
}
